// Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
//
// Licensed under the Mulan PSL v2.
// You can use this file according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of the License at
//
//     http://license.coscl.org.cn/MulanPSL2
//
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
// FOR MORE DETAILS.

/*
 * @Author: qiulin_JXGM ql1746365080@gmail.com
 * @Date: 2024-10-11 15:36:29
 * @LastEditors: qiulin 1746365080@qq.com
 * @LastEditTime: 2025-01-02 17:17:58
 * @FilePath: \SGFEM\Import\BDFImport\BulkData\Constraint\RBE3Parser.cpp
 */

#include "Import/BDFImport/BulkData/Constraint/RBE3Parser.h"

#include <algorithm>
#include <cstdint>
#include <iostream>

#include <boost/algorithm/string.hpp>

#include "Utility/Logging/SGLogger.h"

#include "DBManager/DBServiceFactory.h"
#include "DBManager/IService/Input/Constraint/IRBE3Service.h"

#include "Import/BDFImport/BDFParserBase.h"

BULKDATA_ENTRY_PARSER_REG (RBE3);

using namespace SG::DBManager;
using namespace SG::Import;
using namespace SG::Import::BDF;
using namespace SG::DataStructure;
/*
// file://./../../Doc/MarkDown/BulkData/RBE3/RBE3.md>
*/

enum RBARIndex : std::uint8_t
{
    RBARIndex_EID     = 1,
    RBARIndex_REFGRID = 3,  // Reference grid point identification number. (Integer > 0)
    RBARIndex_REFC    = 4,  // Component numbers at the reference grid point. (Any of the integers 1 through 6 with no embedded blanks.)
};

enum WTCGTYPE : std::uint8_t
{
    WTCGTYPE_WT = 1,  // Weighting factor for components of motion on the following entry at grid points Gi,j.(Real)
    WTCGTYPE_C =
        2,  // Component numbers with weighting factor WTi at grid points Gi,j. (Any of the integers 1 through 6 with no embedded blanks.)
    WTCGTYPE_G = 3,  // Grid points with components Ci that have weighting factor WTi in the averaging equations. (Integer > 0)
};

namespace
{
    static bool s_isHaveUM    = false;
    static bool s_isHaveAlpha = false;

    /**
     * @brief 解析 WTCG 信息并填充 RBE3Data 结构体。
     *
     * 该函数接收一个包含 WTCG 数据的字符串向量（WTCGInfo），并将其解析为结构化的格式（RBE3Data::WTCG）。解析后的数据存储在提供的
     * rbe3Data 对象中。
     *
     * @param WTCGInfo 一个字符串向量的引用，包含 WTCG 信息。
     *                 - 第一个元素表示 wti，类型为 double。
     *                 - 第二个元素表示 c，类型为 long long 整型。
     *                 - 剩下的元素表示 G 值，类型为 long long 整型。
     * @param rbe3Data 一个 RBE3Data 对象的引用，存储解析后的 WTCG 数据。
     */
    void parseWTCG (std::vector<std::string>& WTCGInfo, FEM::RBE3Data& rbe3Data)
    {
        // 临时变量，用于存储解析后的 WTCG 数据
        FEM::RBE3Data::WTCG tempwtcg;

        // 解析第一个元素，将其转换为 double 类型并赋值给 wti
        tempwtcg.m_wt1 = convertToReal (WTCGInfo[0]);

        // 解析第二个元素，将其转换为 long long 整型并赋值给 c
        tempwtcg.m_c = convertToI64 (WTCGInfo[1]);

        // 从第三个元素开始，解析剩下的所有元素并将它们转换为 long long 整型，然后存储到 G 向量中
        for (size_t curIndex = 2; curIndex < WTCGInfo.size (); curIndex++)
        {
            tempwtcg.m_g.push_back (convertToI64 (WTCGInfo[curIndex]));
        }

        // 将解析后的 tempwtcg 添加到 rbe3Data 的 WTCG 向量中
        rbe3Data.m_WTCG.push_back (tempwtcg);
    }

    /**
     * @brief 分离并解析 WTCG 信息，将其填充到 RBE3Data 结构体。
     *
     * 该函数分离输入的 dividedEntryInfo，解析 WTCG 数据并填充到 rbe3Data 对象中。
     *
     * @param dividedEntryInfo 分割后的条目信息，包含所有 WTCG 数据。
     * @param UMBeginRow UM 行的起始索引。
     * @param rbe3Data RBE3Data 对象的引用，存储解析后的 WTCG 数据。
     */
    void separateWTCG (std::vector<std::string>& dividedEntryInfo, size_t UMBeginRow, FEM::RBE3Data& rbe3Data)
    {
        size_t   beginColumnIndex = 5;                      // WTCG 的第一行从 index = 5 开始
        WTCGTYPE curWTCGTYPE      = WTCGTYPE::WTCGTYPE_WT;  // 记录当前字符串是 WT、C、G，默认从 WT 开始

        std::vector<std::string> tempWTCG;                  // 每个 WTCG 的临时存储位置
        tempWTCG.reserve (dividedEntryInfo.size ());

        // 不存在UM的情况下，如果存在Alpha则UMBeginRow--
        if (!s_isHaveUM && s_isHaveAlpha)
        {
            UMBeginRow--;
        }

        for (size_t curRow = 0; curRow < UMBeginRow; curRow++)
        {
            // 除开第一行外，其余均从 index = 1 开始
            if (curRow != 0)
            {
                beginColumnIndex = 1;
            }

            for (size_t fieldsColumn = beginColumnIndex; fieldsColumn < 9; fieldsColumn++)
            {
                // 计算当前字段的索引
                const size_t curIndex  = curRow * 10 + fieldsColumn;
                std::string& curStrKey = dividedEntryInfo[curIndex];

                // 检查当前字段是否为空白
                bool const isEmpty = is_all_space (curStrKey);

                // 如果当前字段为空白，跳过处理
                if (isEmpty)
                {
                    continue;
                }

                bool isFloat;  // 判断当前字符串是否为浮点数，用来确定下一个WTCG的起始
                // 根据当前 WTCG 类型进行解析
                switch (curWTCGTYPE)
                {
                case WTCGTYPE::WTCGTYPE_WT:
                    if (!tempWTCG.empty ())
                    {
                        parseWTCG (tempWTCG, rbe3Data);
                    }
                    tempWTCG.clear ();
                    tempWTCG.push_back (curStrKey);
                    curWTCGTYPE = WTCGTYPE::WTCGTYPE_C;
                    break;
                case WTCGTYPE::WTCGTYPE_C:
                    tempWTCG.push_back (curStrKey);
                    curWTCGTYPE = WTCGTYPE::WTCGTYPE_G;
                    break;
                case WTCGTYPE::WTCGTYPE_G:
                    isFloat = std::any_of (curStrKey.begin (), curStrKey.end (), [] (char c) { return c == '.'; });
                    if (isFloat)
                    {
                        // 如果当前字段是浮点数，则回退列索引
                        fieldsColumn--;
                        curWTCGTYPE = WTCGTYPE::WTCGTYPE_WT;
                    }
                    else
                    {
                        tempWTCG.push_back (curStrKey);
                    }
                    break;
                default:
                    break;
                }
            }
        }

        // 处理最后一个 WTCG
        parseWTCG (tempWTCG, rbe3Data);
    }

    /**
     * @brief 解析 UM 信息并填充 RBE3Data 结构体。
     *
     * @param dividedEntryInfo 分割后的条目信息，包含 UM 数据。
     * @param UMBeginRow UM 的起始行。
     * @param ALPHABeginRow ALPHA 的起始行。
     * @param rbe3Data RBE3Data 对象的引用，存储解析后的 UM 数据。
     */
    void parseUM (std::vector<std::string>& dividedEntryInfo, size_t UMBeginRow, size_t ALPHABeginRow, FEM::RBE3Data& rbe3Data)
    {
        // 预留空间以减少内存重新分配的次数
        rbe3Data.m_GM.reserve ((ALPHABeginRow - UMBeginRow) * 3);

        for (size_t curRow = UMBeginRow; curRow < ALPHABeginRow; curRow++)
        {
            for (size_t fieldsColumn = 2; fieldsColumn < 8; fieldsColumn += 2)
            {
                // 计算当前字段的索引
                const size_t curIndex  = curRow * 10 + fieldsColumn;
                std::string& curStrKey = dividedEntryInfo[curIndex];

                // 检查当前字段是否为空白
                bool const isEmpty = is_all_space (curStrKey);

                // 如果当前字段为空白，跳过处理
                if (isEmpty)
                {
                    continue;
                }

                // 解析 UM 数据并存储到 rbe3Data 中
                std::string& nextStrKey = dividedEntryInfo[curIndex + 1];

                rbe3Data.m_GM.push_back ({ convertToI64 (curStrKey), convertToI64 (nextStrKey) });
            }
        }
    }

    /**
     * @brief 解析 ALPHA 信息并填充 RBE3Data 结构体。
     *
     * @param dividedEntryInfo 分割后的条目信息，包含 ALPHA 数据。
     * @param ALPHABeginRow ALPHA 的起始行。
     * @param rowNum 总行数。
     * @param rbe3Data RBE3Data 对象的引用，存储解析后的 ALPHA 数据。
     */
    void parseALPHA (std::vector<std::string>& dividedEntryInfo, size_t ALPHABeginRow, size_t rowNum, FEM::RBE3Data& rbe3Data)
    {
        // 如果 ALPHABeginRow 等于总行数，表示没有 ALPHA 数据
        if (ALPHABeginRow == rowNum)
        {
            return;
        }

        // 解析 ALPHA 数据并存储到 rbe3Data 中
        rbe3Data.m_alpha = convertToReal (dividedEntryInfo[ALPHABeginRow * 10 + 2]);
    }

    /**
     * @brief 确认 UM 和 ALPHA 的起始行。
     *
     * @param dividedEntryInfo 分割后的条目信息。
     * @param rowNum 总行数。
     * @param UMBeginRow UM 的起始行。
     * @param ALPHABeginRow ALPHA 的起始行。
     */
    void confirmRowNum (std::vector<std::string>& dividedEntryInfo, size_t& rowNum, size_t& UMBeginRow, size_t& ALPHABeginRow)
    {
        rowNum        = dividedEntryInfo.size () / 10;
        UMBeginRow    = rowNum;  // 后续需要比较大小确定generalEndRow，因此先赋值rowNum
        ALPHABeginRow = rowNum;  // 后续需要比较大小确定generalEndRow，因此先赋值rowNum

        for (size_t curRow = 0; curRow < rowNum; curRow++)
        {
            size_t const index = curRow * 10 + 1;
            boost::trim (dividedEntryInfo[index]);
            if ("UM" == dividedEntryInfo[index])
            {
                UMBeginRow = curRow;
                s_isHaveUM = true;
            }
            if ("ALPHA" == dividedEntryInfo[index])
            {
                ALPHABeginRow = curRow;
                s_isHaveAlpha = true;
            }
        }
    }

}  // namespace

/**
 * @brief 解析 RBE3 数据并存储到数据库中。
 *
 * 该函数解析输入的 EntryInfo，提取 RBE3 相关信息，并通过 dbServiceFactory 存储到数据库中。
 *
 * @param dbServiceFactory 数据库服务工厂的智能指针。
 * @param EntryInfo 包含 RBE3 数据的字符串向量。
 * @return 如果解析成功则返回 true，否则返回 false。
 */
SG::DataStructure::Common::Status BDF::BULKDATA::ParseRBE3 (const std::shared_ptr<SG::DBManager::DBServiceFactory>& dbServiceFactory,
                                                            std::vector<std::string>&                               dividedEntryInfo)
{
    FEM::RBE3Data tempData;
    s_isHaveUM = s_isHaveAlpha = false;
    // TODO(bug 001) m_domainId 的正确填写
    tempData.m_domainId = 1;

    // 解析固定位置信息
    tempData.m_id   = convertToI64 (dividedEntryInfo[RBARIndex_EID]);
    tempData.m_refg = convertToI64 (dividedEntryInfo[RBARIndex_REFGRID]);
    tempData.m_refc = convertToI64 (dividedEntryInfo[RBARIndex_REFC]);

    // 声明 UM，ALPHA 的起始行变量，假设 UM 在 ALPHA 前面
    size_t rowNum;         // rbe3 词条总行数
    size_t UMBeginRow;     // UM 起始行，row 从 0 开始
    size_t ALPHABeginRow;  // ALPHA 起始行，row 从 0 开始
    confirmRowNum (dividedEntryInfo, rowNum, UMBeginRow, ALPHABeginRow);

    // 解析 WTCG
    tempData.m_WTCG.reserve (3 * rowNum);
    separateWTCG (dividedEntryInfo, UMBeginRow, tempData);

    // 解析 UM
    if (s_isHaveUM)
    {
        parseUM (dividedEntryInfo, UMBeginRow, ALPHABeginRow, tempData);
    }
    // 解析 ALPHA
    if (s_isHaveAlpha)
    {
        parseALPHA (dividedEntryInfo, ALPHABeginRow, rowNum, tempData);
    }
    // 将解析后的数据添加到数据库中
    return dbServiceFactory->get<IRBE3Service> ()->Add (tempData);
}